//
//  GQJBlockViewController.m
//  TotalDemo
//
//  Created by gujian on 16/7/8.
//  Copyright © 2016年 gujian. All rights reserved.
//

#import "GQJBlockViewController.h"

typedef void(^TestBlock)(void);
typedef void(^GQJBlock)(BOOL flag);
typedef void(^AutaBlock)(void);
typedef void (^BLK)(id);

@interface GQJBlockViewController ()

@property (nonatomic, copy) TestBlock GQJTestBlock;
@property (nonatomic, strong) NSString *titleStr;

@property (nonatomic, copy) GQJBlock gqjBlock;

@property (nonatomic, strong) NSMutableDictionary *cacheDict;

@end

AutaBlock block;
BLK blk;

@implementation GQJBlockViewController

- (void)loadView
{
    [super loadView];
    LotLog(@"");
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    LotLog(@"");

    self.title = @"测试block";
    
    self.titleStr = @"测试block";
    
    
    [self test1];
    [self testVariableScope];
//    MRC 下会出错
//    block();
//    block();
//    block();
    
    [self testTempBlock];
//    MRC 下会出错
    blk([[NSObject alloc] init]);
    blk([[NSObject alloc] init]);
    blk([[NSObject alloc] init]);
    
    
    LotLog(@"1retainCount:%ld",CFGetRetainCount((__bridge CFTypeRef)self));
    
    __weak __typeof(self) weakSelf = self;
    LotLog(@"2reatinCount:%ld",CFGetRetainCount((__bridge CFTypeRef)self));
    
    
    __strong __typeof(self) strongSelf = weakSelf;
    LotLog(@"3retainCount:%ld",CFGetRetainCount((__bridge CFTypeRef)self));
    
    
    self.cacheDict = [[NSMutableDictionary alloc] init];
    
    self.cacheDict[@"1"] = @(1);
    
    LotLog(@"****self.cache:%@",_cacheDict[@"1"]);
    
    [self testBlockBlock];
    
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    LotLog(@"");

}

- (void)viewDidAppear:(BOOL)animated
{
    [super viewDidAppear:animated];
    LotLog(@"");
}

- (void)viewWillDisappear:(BOOL)animated
{
    [super viewWillDisappear:animated];
    LotLog(@"");

}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    LotLog(@"");

}


//retain block one
- (void)test1
{
#pragma clang diagnostic push

#pragma clang diagnostic ignored "-Warc-retain-cycles"
    
     NSLog(@"1self.retainCount:%ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
    self.GQJTestBlock = ^(void){
        NSLog(@"******%@",_titleStr);
        NSLog(@"2self.retainCount:%ld",CFGetRetainCount((__bridge CFTypeRef)(self)));
    };
    
    
    if (self.GQJTestBlock) {
        self.GQJTestBlock();
    }

    
#pragma clang diagnostic pop
}


//retain block two
- (void)test2
{
    _GQJTestBlock = ^{
    
        [self logTheInfo];
    };
    
    _GQJTestBlock();
}

//normal block three
- (void)test3
{
    TestBlock test = ^{
        NSLog(@"******%@",_titleStr);
    };
    
    test();
}

//normal block four
- (void)test4
{
    TestBlock test = ^{
        [self logTheInfo];
    };
    
    test();
}

//测试变量作用域  mrc下会崩溃 需copy block
- (void)testVariableScope
{
    NSString *str = @"局部变量，分配在栈上";
//    id array = [[NSMutableArray alloc] init];
    block = ^{
    
        NSLog(@"******%s%@",__func__,str);
//        [array addObject:[[NSObject alloc] init]];
//        NSLog(@"array count = %ld",(unsigned long)[array count]);
        
    };
}

- (void)testTempBlock
{
    id array = [[NSMutableArray alloc] init];
    blk = ^(id obj){
        [array addObject:obj];
        NSLog(@"array count = %ld", (long)[array count]);
    
    };
}

- (void)logTheInfo
{
    NSLog(@"******%@",_titleStr);
}

- (void)testBlockBlock
{
    __block NSString *str = [NSString stringWithFormat:@"123"];
    void(^TempBlock)(int i) = ^(int i){
      
        NSLog(@"%@str:%@",@(i),str);
    };
    
    TempBlock(1);
    str = @"456";
    TempBlock(2);
    
    /**
        1.结果为 str:123
        2.结果为 str:456
     */
    
    NSString *str1 = [NSString stringWithFormat:@"789"];
    void(^TempBlock1)(int i) = ^(int i){
        NSLog(@"%@str:%@",@(i),str1);
    };
    TempBlock1(3);
    str1 = @"012";
    TempBlock1(4);
    
}

- (void)dealloc
{
    LotLog(@"dealloc");
}


/**
 *  block有三种类型:
 *  1._NSConcreateStackBlock--__NSStackBlock        存储在栈上；
 *  2._NSConcreateGlobalBlock--__NSGlobalBlock      存储在程序的数据区域（text段）；
 *  3._NSConcreateMallocBlock--__NSMallocBlock      存储在堆上
 *
 *  NSGlobalBlock:在block内部没有引用任何外部变量
 *  NSStackBlock:在block内部有引用外部变量
 *  NSMallocBlock:如果NSStackBlock需要在其作用域外部使用的时候，在MRC模式下需手动将其copy到堆上，NSMalloc支持retain、release,对其引用计数+1或-1，copy不会生成新的对象，只是增加了一次引用，类似retain;
 而ARC模式下回自动对齐进行copy，不需要自己手动管理。
 ARC模式下，id和对象类型在灭有明确指定所有权修饰符时，默认为__strong修饰符（详见Objective高级编程p30）
 
 http://www.jianshu.com/p/61ff80d310f4
 
 */
- (void)testBlock
{
    //    NSInteger num = 100;
    //    BOOL flag = YES;
    //
    //
    //    void (^block)();
    //    if (flag) {
    //        block = ^{
    //            NSLog(@"blockA:%@",@(num));
    //        };
    //    }else
    //    {
    //        block = ^{
    //            NSLog(@"blockB");
    //        };
    //    }
    //
    //
    //
    //    block();
    //
    //    NSLog(@"malloc blockA:%@",block);
    //
    //    NSLog(@"global blockB:%@",block);
    //
    //
    //
    //    NSLog(@"stack Block:%@",^{NSLog(@"stackBlock:%@",@(num));});
    
    ////    MRC下block分析
    //    [self example];
    
}

////MRC下分析
//- (void)example
//{
//    NSMutableArray *array = [NSMutableArray array];
//    [self example_addBlocktoArrar:array];
//    void(^block)() = array[0];
//    block();
//}
//
///**
// *  在MRC下会有发生崩溃的机会
// *  因为此时的block分配在栈上，超出作用域后，所指向的内存被回收，
// *  如果此块内存被覆写，则会发生崩溃现象
// *  修改方法，对block执行copy操作，增加retainCount
// *  [array addObject:[^{NSLog(@"%cn",b)} copy]];
// */
//- (void)example_addBlocktoArrar:(NSMutableArray *)array
//{
//    char b = 'B';
//    [array addObject:^{
//        NSLog(@"%cn",b);
//    }];
//}



@end
